import { Config, Inject, Provide } from '@midwayjs/decorator';
import { BaseService, CoolCommException } from '@cool-midway/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Between, LessThan, Repository } from 'typeorm';
import { UserAnalysisEntity } from '../entity/analysis';
import { Context } from '@midwayjs/koa';
import axios from 'axios';
import { UserWxService } from './wx';
import moment = require('moment');
require('moment/locale/zh-cn')
moment.updateLocale('zh-cn', {
    week: {
        dow: 1,
    }
});
import { DictInfoService } from '../../dict/service/info';
/**
 * 数据分析
 */
@Provide()
export class UserAnalysisService extends BaseService {

    @InjectEntityModel(UserAnalysisEntity)
    userAnalysisEntity: Repository<UserAnalysisEntity>;

    @Inject()
    ctx: Context;

    @Inject()
    userWxService: UserWxService;

    @Inject()
    dictInfoService: DictInfoService;
    /**
     * 昨日访问量
     */
    async getTotalVisits() {
        // 总访问量
        let totalVisits = await this.getAnalysisDetail('8000088:8', "")
        // 周同比
        let total_visits_chart = await this.getActiveTrends('1000001:6','week')
        // 昨日访问量
        let yesterday_visits = await this.getAnalysisDetail("1000001:6", "")
        return {
            totalVisits,
            yesterday_visits,
            total_visits_chart
        }
    }

    /**
     * 总用户数
     */
    async getTotalUsers() {
        // 用户总数
        let totalUsers = await this.getAnalysisDetail('9000099:9', "")
        // 周同比
        let total_users_week = await this.getAnalysisDetail('9000099:9', "week")
        // 月同比
        let total_users_month = await this.getAnalysisDetail('9000099:9', "month")
        // 今日用户
        let registered_users = await this.getAnalysisDetail("1000011:3", "")
        return {
            totalUsers,
            total_users_week,
            total_users_month,
            registered_users
        }
    }
    /**
     * 昨日概况
     */
    async getYesterdayOverview() {
        // 获取活跃用户
        let active_metric = "1000001:5"
        // 昨天
        let active_users = await this.getAnalysisDetail(active_metric, "")
        // 前天
        let active_users_yesterday = await this.getAnalysisDetail(active_metric, "yesterday")
        // 上周的昨天
        let active_users_week = await this.getAnalysisDetail(active_metric, "week")
        // 上个月的昨天
        let active_users_month = await this.getAnalysisDetail(active_metric, "month")

        // 获取注册用户
        let registered_metric = "1000011:3"
        let registered_users = await this.getAnalysisDetail(registered_metric, "")
        let registered_users_yesterday = await this.getAnalysisDetail(registered_metric, "yesterday")
        let registered_users_week = await this.getAnalysisDetail(registered_metric, "week")
        let registered_users_month = await this.getAnalysisDetail(registered_metric, "month")
        // 获取人均访问次数
        let visits_metric = "1000001:8"
        let visits = await this.getAnalysisDetail(visits_metric, "")
        let visits_yesterday = await this.getAnalysisDetail(visits_metric, "yesterday")
        let visits_week = await this.getAnalysisDetail(visits_metric, "week ")
        let visits_month = await this.getAnalysisDetail(visits_metric, "month")
        // 获取人均停留时长
        let remain_metric = '1000001:7'
        let remain = await this.getAnalysisDetail(remain_metric, "")
        let remain_yesterday = await this.getAnalysisDetail(remain_metric, "yesterday")
        let remain_week = await this.getAnalysisDetail(remain_metric, "week")
        let remain_month = await this.getAnalysisDetail(remain_metric, "month")
        return {
            active_users,
            active_users_yesterday: this.getPercentage(active_users, active_users_yesterday),
            active_users_week: this.getPercentage(active_users, active_users_week),
            active_users_month: this.getPercentage(active_users, active_users_month),
            registered_users,
            registered_users_yesterday: this.getPercentage(registered_users, registered_users_yesterday),
            registered_users_week: this.getPercentage(registered_users, registered_users_week),
            registered_users_month: this.getPercentage(registered_users, registered_users_month),
            visits,
            visits_yesterday: this.getPercentage(visits, visits_yesterday),
            visits_week: this.getPercentage(visits, visits_week),
            visits_month: this.getPercentage(visits, visits_month),
            remain,
            remain_yesterday: this.getPercentage(remain, remain_yesterday),
            remain_week: this.getPercentage(remain, remain_week),
            remain_month: this.getPercentage(remain, remain_month),
        }
    }
    /**
     * 获取获取百分比
     */
    getPercentage(number, preNumber) {
        let users_week = 100
        if (preNumber == 0 && number == 0) {
            users_week = 0
        } else if (number == 0) {
            users_week = -preNumber * 100
        } else if (preNumber == 0) {
            users_week = number * 100
        } else {
            users_week = parseFloat((100 - ((number / preNumber) * 100)).toFixed(2)) * (number > preNumber ? 1 : -1)
        }
        return users_week
    }
    /**
     * 获取详细数据
     */
    async getAnalysisDetail(metric: string, type: string = "") {
        let time_label = moment().subtract(1, 'days').startOf('day').toDate()
        if (type == 'yesterday') {
            time_label = moment().subtract(2, 'days').startOf('day').toDate()
        } else if (type == 'week') {
            time_label = moment().subtract(7, 'days').toDate()
        } else if (type == 'month') {
            time_label = moment().subtract(1, 'months').toDate()
        }
        let data = await this.userAnalysisEntity.findBy({ metric, time_label })
        let metric_value = 0
        data.forEach(item => {
            let value = item.metric_value ?? 0
            metric_value = value + metric_value
        })
        return metric_value
    }
    /**
     * 访问分析
     */
    async getAccessTrends(type) {

    }
    /**
     * 近30天活跃趋势
     */
    async getActiveTrends(metric, type = "months") {
        let start_date = moment().subtract(1, 'months').toDate()

        if (type == 'week') {
            start_date = moment().subtract(1, 'weeks').toDate()
        }
        let end_date = moment().toDate()
        let data = await this.userAnalysisEntity.findBy({ metric, time_label: Between(start_date, end_date) })
        let datas: number[] = []
        let dates: Date[] = []
        data.forEach(item => {
            datas.push(item.metric_value)
            dates.push(item.time_label)
        })
        return {
            datas,
            dates
        }
    }
    /**
     * 统计每天的访问数据
     */
    async getDayAnalysisData(granularity: number, time: string = "") {
        time = time ? time : moment().format("yyyy-MM-DD")
        let start = moment()
        // 活跃用户
        await this.getActiveUsers(granularity, time)
        // 注册用户
        await this.getRegisteredUser(granularity, time)
        // 分享用户
        await this.getSharedUser(time)
        let end = moment()
        var duration = moment.duration(end.diff(start));
        return `获取成功,共耗时${duration.as('seconds')}s`
    }
    /**
     * 付费金额 
     * granularity number 是 时间粒度
     */
    async getPayUsers(granularity: number, time: string = "") {
        // 付费金额
        await this.getGameAnalysisData({ time, metric: '1000022:3', granularity: 24 })
        // 新增付费金额
        await this.getGameAnalysisData({ time, metric: '1000023:4', granularity })
        // 活跃用户人均访问次数
        await this.getGameAnalysisData({ time, metric: '1000001:8', granularity })
        // 活跃用户人均停留时长
        await this.getGameAnalysisData({ time, metric: '1000001:7', granularity })
        // 活跃用户次日留存
        await this.getGameAnalysisData({ time, metric: '1000010:3', granularity: 24 })
        // 活跃用户七日留存
        await this.getGameAnalysisData({ time, metric: '1000010:5', granularity: 24 })
        // 活跃用户年龄画像
        await this.getGameAnalysisData({ time, metric: '1000005:4', granularity })
    }
    /**
     * 活跃用户
     * granularity number 是 时间粒度
     */
    async getActiveUsers(granularity: number, time: string = "") {
        // 活跃用户数
        await this.getGameAnalysisData({ time, metric: '1000001:5', granularity: 24 })
        // 活跃用户访问次数
        await this.getGameAnalysisData({ time, metric: '1000001:6', granularity })
        // 活跃用户人均访问次数
        await this.getGameAnalysisData({ time, metric: '1000001:8', granularity })
        // 活跃用户人均停留时长
        await this.getGameAnalysisData({ time, metric: '1000001:7', granularity })
        // 活跃用户次日留存
        await this.getGameAnalysisData({ time, metric: '1000010:3', granularity: 24 })
        // 活跃用户七日留存
        await this.getGameAnalysisData({ time, metric: '1000010:5', granularity: 24 })
        // 活跃用户年龄画像
        await this.getGameAnalysisData({ time, metric: '1000005:4', granularity })
        // 累加访问次数
        await this.summationVisits(time)
    }
    /**
     * 累加访问次数
     */
    async summationVisits(time: string = "") {
        let metric = '8000088:8'
        let { start_time } = this.getGranularityTime(24, time)
        let detail = await UserAnalysisEntity.findOneBy({ metric, timestamp: start_time })
        let pre_time = moment(time).subtract(2, "days").startOf('day').unix()
        let data = await UserAnalysisEntity.findOneBy({ metric: '1000001:6', timestamp: start_time })
        let pre_data = await UserAnalysisEntity.findOneBy({ metric, timestamp: pre_time })
        let metric_value = data?.metric_value
        if (pre_data) {
            metric_value = pre_data?.metric_value + data?.metric_value
        }
        if (detail) {
            await this.userAnalysisEntity.update({ id: detail.id }, { metric_value })
        } else {
            let name = await this.dictInfoService.getValues(metric, 'analysis')
            await this.userAnalysisEntity.save({ metric, name, timestamp: data.timestamp, group_dimension_list: data.group_dimension_list, time_label: data.time_label, metric_value })
        }
    }
    /**
     * 注册用户
     * granularity number 是 时间粒度
     */
    async getRegisteredUser(granularity: number, time: string = "") {
        // 注册用户数	
        await this.getGameAnalysisData({ time, metric: '1000011:3', granularity })
        // 注册用户次日留存
        await this.getGameAnalysisData({ time, metric: '1000021:3', granularity: 24 })
        // 注册用户七日留存
        await this.getGameAnalysisData({ time, metric: '1000021:5', granularity: 24 })
        // 注册用户年龄画像
        await this.getGameAnalysisData({ time, metric: '1000013:5', granularity })
        // 注册用户性别画像
        await this.getGameAnalysisData({ time, metric: '1000015:4', granularity })
        // 累加注册用户
        await this.summationRegister(time)
    }
    /**
     * 累加注册用户
     */
    async summationRegister(time: string = "") {
        let metric = '9000099:9'

        let { start_time } = this.getGranularityTime(24, time)
        let detail = await UserAnalysisEntity.findOneBy({ metric: metric, timestamp: start_time })
        let pre_time = moment(time).subtract(2, "days").startOf('day').unix()
        let data = await UserAnalysisEntity.findOneBy({ metric: '1000011:3', timestamp: start_time })
        let pre_data = await UserAnalysisEntity.findOneBy({ metric, timestamp: pre_time })
        let metric_value = data?.metric_value
        if (pre_data) {
            metric_value = pre_data?.metric_value + data?.metric_value
        }
        if (detail) {
            await this.userAnalysisEntity.update({ id: detail.id }, { metric_value })
        } else {
            let name = await this.dictInfoService.getValues(metric, 'analysis')
            await this.userAnalysisEntity.save({ metric, name, timestamp: data.timestamp, group_dimension_list: data.group_dimension_list, time_label: data.time_label, metric_value })
        }
    }
    /**
     * 分享用户
     */
    async getSharedUser(time: string = "") {
        // 分享用户数	
        await this.getGameAnalysisData({ time, metric: '1000028:4', granularity: 24 })
        // 分享次数
        await this.getGameAnalysisData({ time, metric: '1000028:3', granularity: 24 })
        // 人均分享次数
        await this.getGameAnalysisData({ time, metric: '1000028:7', granularity: 24 })
        // 分享率	
        await this.getGameAnalysisData({ time, metric: '1000028:5', granularity: 24 })
        // 分享用户年龄画像
        await this.getGameAnalysisData({ time, metric: '1000188:6', granularity: 24 })
        // 分享用户性别画像
        await this.getGameAnalysisData({ time, metric: '1000189:6', granularity: 24 })
    }

    /**
     * 获取小游戏分析数据
     * metric string 必填 指标 id
     * granularity number 是 时间粒度
     * start_time number 是 开始时间戳(需按查询粒度的零时刻对齐)
     * end_time	number 是 结束时间戳(需按查询粒度的零时刻对齐)
     * filter_list Array.<Object> 否	维度筛选列表，支持对1个或多个维度做条件过滤
     * group_list Array.<string> 否	维度分组列表，展开单个粒度周期下的1个或多个维度的取值分布
     * access_token string 是 接口调用凭证
     */
    async getGameAnalysisData({ time, metric, granularity, filter_list = [], group_list = [] }) {

        let { start_time, end_time } = this.getGranularityTime(granularity, time)
        const token = await this.userWxService.getWxToken();
        const ticket = await axios.post(
            'https://api.weixin.qq.com/datacube/getgameanalysisdata?access_token=' + token,
            {
                metric,
                start_time,
                end_time,
                granularity,
                filter_list,
                group_list
            }
        );
        let data = await UserAnalysisEntity.findOneBy({ metric, timestamp: start_time })
        if (!ticket.data?.errcode) {
            let detail = ticket.data?.data_list[0]
            if (data) {
                await this.userAnalysisEntity.update({ id: data.id }, { metric_value: detail.metric_value })
            } else {
                let name = await this.dictInfoService.getValues(metric, 'analysis')
                await this.userAnalysisEntity.save({ metric, name, ...detail })
            }
        }
        return { metric, ...ticket.data }

    }
    /**
     * 获取自然天或自然月的时间戳
     * granularity number 是 时间粒度
     */
    getGranularityTime(granularity, time: string = "") {
        let start_time = 0
        let end_time = 0
        if (granularity == 24) {
            start_time = moment(time).subtract(1, 'days').startOf('day').unix()
            end_time = moment(time).startOf('day').unix()
        } else if (granularity == 30) {
            start_time = moment(time).startOf('month').unix()
            end_time = moment(time).clone().endOf('month').startOf('month').add(1, 'month').unix()
        } else {
            start_time = moment(time).startOf('week').unix()
            end_time = moment(time).clone().startOf('week').add(1, 'weeks').unix()
        }
        return { start_time, end_time }
    }

    /**
     * 获取小游戏广告汇总数据
     * page	是	返回第几页数据
     * page_size	是	当页返回数据条数
     * start_date	是	获取数据的开始时间 yyyy-mm-dd
     * end_date	是	获取数据的结束时间 yyyy-mm-dd
     * ad_slot	否	广告位类型名称
     */
    async getAdposGeneral(params) {
        return {
            "base_resp": {
                "err_msg": "ok",
                "ret": 0
            },
            "list": [
                {
                    "slot_id": 3030046789020061,
                    "ad_slot": "SLOT_ID_WEAPP_INTERSTITIAL",
                    "date": "2020-04-13",
                    "req_succ_count": 443610,
                    "exposure_count": 181814,
                    "exposure_rate": 0.409850995,
                    "click_count": 10095,
                    "click_rate": 0.055523777,
                    "income": 52175,
                    "ecpm": 286.969100289
                }
            ],
            "summary": {
                "req_succ_count": 4406394,
                "exposure_count": 1797225,
                "exposure_rate": 0.407867522,
                "click_count": 100167,
                "click_rate": 0.055734257,
                "income": 578003,
                "ecpm": 321.608591022
            },
            "total_num": 1
        }
        const token = await this.userWxService.getWxToken();
        const ticket = await axios.get(
            'https://api.weixin.qq.com/publisher/stat?action=publisher_adpos_general&access_token=' + token,
            {
                params: {
                    page: params.page,
                    page_size: params.size,
                    start_date: params.start_date,
                    end_date: params.end_date,
                    ad_slot: params.ad_slot,
                }
            }
        );
        console.log(ticket.data)
        return ticket.data
    }

    /**
     * 获取小游戏广告细分数据
     * page	是	返回第几页数据
     * page_size	是	当页返回数据条数
     * start_date	是	获取数据的开始时间 yyyy-mm-dd
     * end_date	是	获取数据的结束时间 yyyy-mm-dd
     * ad_slot	否	广告位类型名称
     * ad_unit_id 否	广告位id
     */
    async getAdunitGeneral(query) {
        const token = await this.userWxService.getWxToken();
        const ticket = await axios.post(
            'https://api.weixin.qq.com/publisher/stat?action=publisher_adunit_general&access_token=' + token,
            {
                page: query.page,
                page_size: query.page_size,
                start_date: query.start_date,
                end_date: query.end_date,
                ad_slot: query.ad_slot,
                ad_unit_id: query.ad_unit_id
            }
        );
        return ticket
    }

    /**
     * 获取小游戏广告位清单
     * page	是	返回第几页数据
     * page_size	是	当页返回数据条数
     * ad_slot	否	广告位类型名称
     */
    async getAdunitList(query) {
        const token = await this.userWxService.getWxToken();
        const ticket = await axios.post(
            'https://api.weixin.qq.com/publisher/stat?action=get_adunit_list&access_token=' + token,
            {
                page: query.page,
                page_size: query.page_size,
                ad_slot: query.ad_slot,
            }
        );
        return ticket
    }

    /**
     * 获取小游戏结算收入数据及结算主体信息
     * page	是	返回第几页数据
     * page_size	是	当页返回数据条数
     * start_date	是	获取数据的开始时间 yyyy-mm-dd
     * end_date	是	获取数据的结束时间 yyyy-mm-dd
     */
    async getSettlement(query) {
        const token = await this.userWxService.getWxToken();
        const ticket = await axios.post(
            'https://api.weixin.qq.com/publisher/stat?action=publisher_settlement&access_token=' + token,
            {
                page: query.page,
                page_size: query.page_size,
                start_date: query.start_date,
                end_date: query.end_date,
            }
        );
        return ticket
    }
}
